#ifndef __people_xml_hpp__
#define __people_xml_hpp__

#include <iostream>
#include <fstream>
#include <string>
#include <map>

#include <cstring>
#include "funcs.hpp"

#include "Person.hpp"
#include "Movie.hpp"

#define ACTORS_LIST    "lists/actors.list"
#define ACTRESSES_LIST "lists/actresses.list"
#define DIRECTORS_LIST "lists/directors.list"
#define PRODUCERS_LIST "lists/producers.list"
#define WRITERS_LIST   "lists/writers.list"
#define NAMES_LIST     "lists/aka-names.list"

#define PEOPLE_XML "xml/people.xml"

typedef void (Person::*add_func)(const string& s, bool b);

string get_name_without_comma(const string& name)
{
  size_t comma = name.rfind(", ");
  if (comma == string::npos) return name;
  else return (name.substr(comma+2) + " " + name.substr(0, comma));
}

string get_name_without_number(const string& name)
{
  size_t parb = name.rfind(" (");
  if ( parb == string::npos ) return name;
  else {
    size_t pare = name.rfind(")");
    return (name.substr(0, parb) + name.substr(pare+1));
  }
}

pair<size_t,size_t> get_movie_title(const string& str, size_t beg)
{
  pair<size_t,size_t> res;

  size_t i = beg;
  while( isspace(str[i]) ) ++i;
  res.first = i;

  res.second = str.find("  ", i) - res.first;

  return res;
}

bool parse_people(map<string, Person, bool(*)(const string&,const string&)>& people, 
		  const char* file, add_func func, const map<string, Movie>& movies)
{
  string line;
  
  ifstream fpeople;
  fpeople.open(file);
  if ( !fpeople.is_open() )
    return false;
  
  map<string, Person, bool(*)(const string&,const string&)>::iterator per_it = people.end();
  while( getline(fpeople, line) ) {
    if ( line == "" ) {
      per_it = people.end();
      continue;
    }

    if ( !isspace(line[0]) ) {
      size_t tab = line.find('\t');

      string name = trim(get_name_without_comma(line.substr(0, tab)));
      
      Person person(name);
      pair<map<string, Person, bool(*)(const string&,const string&)>::iterator,bool> ret;
      ret = people.insert( pair<string,Person>(person.name, person) );
      per_it = ret.first;
      
      // El nom separat per la coma.
      string main_aka = trim(get_name_without_number(per_it->second.name));
      if ( main_aka != per_it->second.name )
	per_it->second.add_aka(main_aka);
      
      pair<size_t, size_t> mov_t = get_movie_title(line, tab);
      string mov_tit = trim(line.substr(mov_t.first, mov_t.second));
      if ( movies.find(mov_tit) != movies.end() )
	(per_it->second.*func)(mov_tit, true);
    } else {
      pair<size_t, size_t> mov_t = get_movie_title(line, 0);
      string mov_tit = trim(line.substr(mov_t.first, mov_t.second));
      if ( movies.find(mov_tit) != movies.end() )
	(per_it->second.*func)(mov_tit, true);
    }
  }
  
  fpeople.close();

  return true;
}

bool parse_all_people(map<string, Person, bool(*)(const string&,const string&)>& people, 
		      const map<string,Movie>& movies)
{
  
  return ( parse_people(people, ACTORS_LIST,    &Person::add_actor, movies)    &&
	   parse_people(people, ACTRESSES_LIST, &Person::add_actor, movies)    &&
	   parse_people(people, DIRECTORS_LIST, &Person::add_director, movies) &&
	   parse_people(people, PRODUCERS_LIST, &Person::add_producer, movies) &&
	   parse_people(people, WRITERS_LIST,   &Person::add_writer, movies) );
}

bool parse_aka_names(map<string, Person, bool(*)(const string&,const string&)>& people)
{
  string line;

  ifstream fnames;
  fnames.open(NAMES_LIST);
  if ( !fnames.is_open() ) {
    cerr << "ERROR OPENING FILE " << NAMES_LIST << endl;
    return false;
  }

  bool ignore = false;
  map<string, Person, bool(*)(const string&,const string&)>::iterator per_it = people.end();
  while( getline(fnames, line) ) {
    if ( line == "" ) {
      ignore = false;
      per_it = people.end();
      continue;
    }

    if ( ignore ) continue;

    if ( per_it == people.end() ) {

      per_it = people.find( get_name_without_comma(line) );
      if ( per_it == people.end() ) {
	cerr << "PERSON NOT FOUND: " << line << " (IGNORING)"<< endl;
	ignore = true;
      }

    } else {

      size_t beg = line.find("(aka ") + 5;
      size_t end = line.length()-1;
      
      string aka = trim(get_name_without_number(get_name_without_comma(line.substr(beg, end-beg))));
      if ( aka != per_it->second.name )
	per_it->second.add_aka(aka);
      
    }
  }

  fnames.close();

  return true;
}

bool gen_people_xml(map<string, Person, bool(*)(const string&,const string&)>& people)
{
  ofstream peoplexml;
  peoplexml.open( PEOPLE_XML );

  if ( !peoplexml.is_open() )
    return false;

  peoplexml << "<?xml version=\"1.0\" encoding=\"utf-8\"?>" << endl;
  peoplexml << "<people xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" \
xsi:noNamespaceSchemaLocation=\"people.xsd\">" << endl;
  map<string, Person, bool(*)(const string&,const string&)>::const_iterator it;
  for(it = people.begin(); it != people.end(); ++it)
    peoplexml << it->second << endl;
  peoplexml << "</people>" << endl;

  peoplexml.close();

  return true;
}

#endif
